package com.xiejr.actuator.socket.abstracts;

import com.xiejr.actuator.enums.RoleEnum;
import com.xiejr.actuator.exceptioin.SocketActuatorException;
import com.xiejr.actuator.socket.WebSocketHelper;
import com.xiejr.actuator.socket.model.Message;
import com.xiejr.actuator.socket.model.SocketClient;
import com.xiejr.actuator.util.WebsocketUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import javax.websocket.*;
import java.net.InetSocketAddress;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: socket-actuator-spring-boot-starter
 * @description: websocket抽象模型
 * @author: xjr
 * @create: 2020-07-10 14:23
 **/
@Slf4j
public abstract class AbstractWebsocketHelper implements WebSocketHelper {
    protected static final Map<String,SocketClient> SOCKET_CLIENTS=new ConcurrentHashMap<>(20);

    protected static final DateTimeFormatter DATE_TIME_FORMATTER=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

    protected static final DateTimeFormatter SECONDS_FORMATTER=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    protected Session session;

    protected String ip;

    protected String uuid;
    @SneakyThrows
    @OnOpen
    public final void onOpen(Session session) {
        try {
            this.session=session;
            this.ip=getRemoteAddress(session);
            this.uuid=this.ip+this.session.getId();
            addSession(session);
            this.open(session);
        }catch (Exception ex){
            log.info("something wrong occurred during the websocket connection");
            throw new SocketActuatorException(ex.getMessage());

        }

    }

    @OnClose
    public final  void onClose(Session session, CloseReason closeReason) {
        SOCKET_CLIENTS.remove(this.uuid);
        this.close(session,closeReason);
    }

    /**
     *
     * @description socket发生错误
     * @param session 错误会话
     * @param throwable 异常
     * @author xiejiarong
     * @date 2020年07月10日 14:21
     */
    @OnError
    public final void onError(Session session, Throwable throwable) throws Throwable {
        this.error(session,throwable);
    }

    @OnMessage
    public final void onMessage(Session session,String message){
        this.message(session,message);
    }

    /**
     *
     * @return java.util.List<com.xiejr.actuator.socket.model.SocketClient>
     * @author xiejr
     * @creed: 获取全局socket连接
     * @date 2020/7/12 12:45
     */

    public static  Map<String,SocketClient> getSocketClients(){
        return SOCKET_CLIENTS;
    }

    /**
     *
     * @description 根据IP移除session
     * @param ip 地址
     * @author xiejiarong
     * @date 2020年07月10日 11:52
     */
    public void removeSessionByUUID(String uuid){
        getSocketClients().remove(uuid);
    }

    /**
     *
     * @description 加入会话中
     * @param session:  加入会话
     * @author xiejiarong
     * @date 2020年07月10日 11:52
     */
    protected SocketClient addSession(Session session) throws Exception{
        LocalDateTime now=LocalDateTime.now();
        removeSessionByUUID(this.uuid);
        String time=SECONDS_FORMATTER.format(now);
        LinkedHashMap<String, Message> history=new LinkedHashMap<>(50);
        history.put(time,new Message("").setFrom(RoleEnum.CLIENT.getCode()).setContent("客户端首次连接").setTo(RoleEnum.SERVER.getCode())
                .setSendTime(DATE_TIME_FORMATTER.format(now)));
        SocketClient socketClient=SocketClient.builder().deviceIp(this.ip).close(false).connectTime(now).lastRefreshTime(now)
                .session(session).history(history).build();
        SOCKET_CLIENTS.put(this.uuid,socketClient);
        return socketClient;
    }

    /**
     *
     * @param session 发生错误的会话
     * @param err  错误信息
     * @return void
     * @author xiejr
     * @creed: 处理错误情况
     * @date 2020/7/12 12:57
     */
    @Override
    public void error(Session session, Throwable err) throws Throwable {
        log.info("error occurred during the topic-socket connection!,reason is {}",err.getMessage());
        session.getBasicRemote().sendText(err.getMessage());
        session.close();
        removeSessionByUUID(this.uuid);
    }

    /**
     *
     * @description 刷新心跳时间
     * @param refreshTime:当前刷新事件
     * @author xiejiarong
     * @date 2020年06月23日 14:14
     */
    protected final void refreshHeart(LocalDateTime refreshTime,String message){
        String time=DATE_TIME_FORMATTER.format(refreshTime);
        SOCKET_CLIENTS.get(this.uuid).setLastRefreshTime(refreshTime).setClose(false).getHistory().put(SECONDS_FORMATTER.format(refreshTime),
                new Message("").setSendTime(time).setTo(RoleEnum.SERVER.getCode())
                        .setContent(message).setFrom(RoleEnum.CLIENT.getCode()));
    }

    /**
     *
     * @description 方法描述
     * @param session: 会话
     * @return ip地址
     * @author xiejiarong
     * @date 2020年07月13日 17:01
     */
    protected String getRemoteAddress(Session session){
        InetSocketAddress ipAddress= WebsocketUtils.getRemoteAddress(session);
        String ip=ipAddress.getAddress().getHostAddress();
        return ip;
    }

}
